#include "CubeApp.h"

#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/constants.hpp>

#include <stdexcept>
#include <array>
#include <cassert>
#include <chrono>

#include "LvCamera.h"
#include "SimpleRenderSystem.h"
#include "KeyboardMovementController.h"


const float PI_2 = glm::two_pi<float>();
const float PI = glm::pi<float>();

CubeApp::CubeApp()
{
	loadGameObjects();

}

CubeApp::~CubeApp()
{
}

void CubeApp::run()
{
	SimpleRenderSystem simpleRenderSystem{ lvDevice, lvRenderer.getSwapChainRendPass() };
	LvCamera camera;
	auto viewerObject = LvGameObject::createGameObject();
	KeyboardMovementController cameraController;

	auto currentTime = std::chrono::high_resolution_clock::now();

	while (!lvWindow.shouldClose())
	{
		glfwPollEvents();

		auto newTime = std::chrono::high_resolution_clock::now();
		float frameTime = std::chrono::duration<float, std::chrono::seconds::period>(newTime - currentTime).count();
		currentTime = newTime;

		cameraController.moveInPlaneZX(lvWindow.getGLFWwindow(), frameTime, viewerObject);
		camera.setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);

		float aspect = lvRenderer.getAspectRatio();
		//camera.setOrthographicProjection(-aspect, aspect, -1, 1, -10, 10);
		camera.setPerspectiveProjection(glm::radians(60.0f), aspect, 0.1f, 100.0f);

		auto commandBuffer = lvRenderer.beginFrame();
		lvRenderer.beginSwapChainRenderPass(commandBuffer);

		simpleRenderSystem.renderGameObjects(commandBuffer, gameObjects, camera);

		lvRenderer.endSwapChainRenderPass(commandBuffer);
		lvRenderer.endFrame();

	}
	vkDeviceWaitIdle(lvDevice.device());
}

//// temporary helper function, creates a 1x1x1 cube centered at offset
//std::unique_ptr<LvModel> createCubeModel(LvDevice& device, glm::vec3 offset)
//{
//    std::vector<LvModel::Vertex> vertices{
//
//        // left face (white)
//        {{-.5f, -.5f, -.5f}, {.9f, .9f, .9f}},
//        {{-.5f, .5f, .5f}, {.9f, .9f, .9f}},
//        {{-.5f, -.5f, .5f}, {.9f, .9f, .9f}},
//        {{-.5f, -.5f, -.5f}, {.9f, .9f, .9f}},
//        {{-.5f, .5f, -.5f}, {.9f, .9f, .9f}},
//        {{-.5f, .5f, .5f}, {.9f, .9f, .9f}},
//
//        // right face (yellow)
//        {{.5f, -.5f, -.5f}, {.8f, .8f, .1f}},
//        {{.5f, .5f, .5f}, {.8f, .8f, .1f}},
//        {{.5f, -.5f, .5f}, {.8f, .8f, .1f}},
//        {{.5f, -.5f, -.5f}, {.8f, .8f, .1f}},
//        {{.5f, .5f, -.5f}, {.8f, .8f, .1f}},
//        {{.5f, .5f, .5f}, {.8f, .8f, .1f}},
//
//        // top face (orange, remember y axis points down)
//        {{-.5f, -.5f, -.5f}, {.9f, .6f, .1f}},
//        {{.5f, -.5f, .5f}, {.9f, .6f, .1f}},
//        {{-.5f, -.5f, .5f}, {.9f, .6f, .1f}},
//        {{-.5f, -.5f, -.5f}, {.9f, .6f, .1f}},
//        {{.5f, -.5f, -.5f}, {.9f, .6f, .1f}},
//        {{.5f, -.5f, .5f}, {.9f, .6f, .1f}},
//
//        // bottom face (red)
//        {{-.5f, .5f, -.5f}, {.8f, .1f, .1f}},
//        {{.5f, .5f, .5f}, {.8f, .1f, .1f}},
//        {{-.5f, .5f, .5f}, {.8f, .1f, .1f}},
//        {{-.5f, .5f, -.5f}, {.8f, .1f, .1f}},
//        {{.5f, .5f, -.5f}, {.8f, .1f, .1f}},
//        {{.5f, .5f, .5f}, {.8f, .1f, .1f}},
//
//        // nose face (blue)
//        {{-.5f, -.5f, 0.5f}, {.1f, .1f, .8f}},
//        {{.5f, .5f, 0.5f}, {.1f, .1f, .8f}},
//        {{-.5f, .5f, 0.5f}, {.1f, .1f, .8f}},
//        {{-.5f, -.5f, 0.5f}, {.1f, .1f, .8f}},
//        {{.5f, -.5f, 0.5f}, {.1f, .1f, .8f}},
//        {{.5f, .5f, 0.5f}, {.1f, .1f, .8f}},
//
//        // tail face (green)
//        {{-.5f, -.5f, -0.5f}, {.1f, .8f, .1f}},
//        {{.5f, .5f, -0.5f}, {.1f, .8f, .1f}},
//        {{-.5f, .5f, -0.5f}, {.1f, .8f, .1f}},
//        {{-.5f, -.5f, -0.5f}, {.1f, .8f, .1f}},
//        {{.5f, -.5f, -0.5f}, {.1f, .8f, .1f}},
//        {{.5f, .5f, -0.5f}, {.1f, .8f, .1f}},
//
//    };
//
//    LvModel::Builder builder;
//    builder.vertices = vertices;
//
//    for (auto& v : builder.vertices) {
//        v.position += offset;
//    }
//    return std::make_unique<LvModel>(device, builder);
//}


// temporary helper function, creates a 1x1x1 cube centered at offset
// temporary helper function, creates a 1x1x1 cube centered at offset with an index buffer
std::unique_ptr<LvModel> createCubeModel(LvDevice& device, glm::vec3 offset)
{
	std::vector<LvModel::Vertex> vertices{
		// left face (white)
		{{-.5f, -.5f, -.5f}, {.9f, .9f, .9f}},
		{{-.5f, .5f, .5f}, {.9f, .9f, .9f}},
		{{-.5f, -.5f, .5f}, {.9f, .9f, .9f}},
		{{-.5f, .5f, -.5f}, {.9f, .9f, .9f}},

		// right face (yellow)
		{{.5f, -.5f, -.5f}, {.8f, .8f, .1f}},
		{{.5f, .5f, .5f}, {.8f, .8f, .1f}},
		{{.5f, -.5f, .5f}, {.8f, .8f, .1f}},
		{{.5f, .5f, -.5f}, {.8f, .8f, .1f}},

		// top face (orange, remember y axis points down)
		{{-.5f, -.5f, -.5f}, {.9f, .6f, .1f}},
		{{.5f, -.5f, .5f}, {.9f, .6f, .1f}},
		{{-.5f, -.5f, .5f}, {.9f, .6f, .1f}},
		{{.5f, -.5f, -.5f}, {.9f, .6f, .1f}},

		// bottom face (red)
		{{-.5f, .5f, -.5f}, {.8f, .1f, .1f}},
		{{.5f, .5f, .5f}, {.8f, .1f, .1f}},
		{{-.5f, .5f, .5f}, {.8f, .1f, .1f}},
		{{.5f, .5f, -.5f}, {.8f, .1f, .1f}},

		// nose face (blue)
		{{-.5f, -.5f, 0.5f}, {.1f, .1f, .8f}},
		{{.5f, .5f, 0.5f}, {.1f, .1f, .8f}},
		{{-.5f, .5f, 0.5f}, {.1f, .1f, .8f}},
		{{.5f, -.5f, 0.5f}, {.1f, .1f, .8f}},

		// tail face (green)
		{{-.5f, -.5f, -0.5f}, {.1f, .8f, .1f}},
		{{.5f, .5f, -0.5f}, {.1f, .8f, .1f}},
		{{-.5f, .5f, -0.5f}, {.1f, .8f, .1f}},
		{{.5f, -.5f, -0.5f}, {.1f, .8f, .1f}},
	};

	for (auto& v : vertices) {
		v.position += offset;
	}

	LvModel::Builder builder;
	builder.vertices = vertices;
	builder.indices = { 0,  1,  2,  0,  3,  1,  4,  5,  6,  4,  7,  5,  8,  9,  10, 8,  11, 9,
						12, 13, 14, 12, 15, 13, 16, 17, 18, 16, 19, 17, 20, 21, 22, 20, 23, 21 };

	return std::make_unique<LvModel>(device, builder);
}
void CubeApp::loadGameObjects()
{
	std::shared_ptr<LvModel> lvModel = createCubeModel(lvDevice, { 0.0f, 0.0f, 0.0f });

	auto cube = LvGameObject::createGameObject();
	cube.model = lvModel;
	cube.transform.translation = { 0.0f, 0.0f, 2.5f };
	cube.transform.scale = { 0.5f, 0.5f, 0.5f };

	gameObjects.push_back(std::move(cube));
}





